package run;

import static log.LogConstants.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Calendar;
import java.util.HashMap;

import javax.swing.Timer;

import log.LogManager;
import run.graphics.ExpeScreen;
import run.graphics.StartDialog;
import run.scenario.GeneratorConstants;
import run.scenario.Scenario;


/**
 * 
 * @author Mathieu Nancel
 *
 */
public class ScenarioManager {

	////////////////////////////////////////////////////////////////////////////
	
//	/**
//	 * Time after the images have been displayed, in ms
//	 */
//	public static final int TIME_ANSWER = 200;
//	
//	public static final int TRIAL_TIME = TIME_ANSWER + TIME_DISPLAY + TIME_INIT;
	
	////////////////////////////////////////////////////////////////////////////	
	
	public enum STATE {
		BLANK, TAP
	}
	
	private STATE currentState = STATE.BLANK;
	
	public enum SESSION {
		GERMAN, ENGLISH
	}
	
	////////////////////////////////////////////////////////////////////////////
	
	public static ScenarioManager INSTANCE;
	
	protected Scenario scenario;
	protected ExpeScreen expeScreen;
	
	protected boolean canStart = false;
	
	protected int participant;
	protected SESSION session;
	protected int currentTrial;
	
	protected LogManager logManager;
	protected LogManager cineLogManager;

	protected boolean quiting = false;
	
	////////////////////////////////////////////////////////////////////////////
	
	protected int timeTapping = -1;
	protected Timer tapTimer;
	protected boolean tapStarted = false;
	
	////////////////////////////////////////////////////////////////////////////
	
	protected int nbTaps = 0;
	protected long lastTap = -1;
	
	////////////////////////////////////////////////////////////////////////////
	
	protected StartDialog dialog;
	
	////////////////////////////////////////////////////////////////////////////
	
	protected HashMap<String, String[]> language = new HashMap<String, String[]>();
	protected HashMap<String, String> text = new HashMap<String, String>();
	
	protected int fontSize = -1; 
	
	////////////////////////////////////////////////////////////////////////////
	
	/**
	 * 
	 */
	public ScenarioManager(String fileName) {
		
		try {
			BufferedReader labelFileReader = new BufferedReader(new FileReader("config_files"+File.separator+"Language.txt"));
			
			String line = "";
			while( (line = labelFileReader.readLine()) != null) {
				
				if (line.startsWith("//")) {
					continue;
				}
				String[] words = line.split("=");
				language.put(words[0], words[1].split(":"));
				
			}
			
			for (String key : language.keySet()) {
				System.out.println(key);
				for (String k2 : language.get(key)) {
					System.out.print("\t" + k2);
				}
				System.out.println();
			}
			
			labelFileReader.close();
			
			//////////////////////////
			
			BufferedReader configFileReader = new BufferedReader(new FileReader("config_files"+File.separator+"parameters.txt"));
			
			line = "";
			while( (line = configFileReader.readLine()) != null) {
				
				if (line.startsWith("//")) {
					continue;
				}
				String[] words = line.split(": ");
				
				if (words[0].contains("Tapping phase duration")) {
					timeTapping = Integer.parseInt(words[1]);
				}
				if (words[0].contains("font size")) {
					fontSize = Integer.parseInt(words[1]);
				}
				
			}
			
			configFileReader.close();
			
			//////////////////////////
						
			BufferedReader readingFileReader = new BufferedReader(new FileReader("config_files"+File.separator+"Reading.txt"));
			
			line = "";
			String currentLanguage = "";
			while( (line = readingFileReader.readLine()) != null) {
				
				if (line.startsWith("//")) {
					continue;
				}
				
				if (line.endsWith("::")) {
					currentLanguage = line.substring(0, line.length()-2);
					text.put(currentLanguage, "");
				} else {
					text.put(currentLanguage, text.get(currentLanguage) + line + "\n");
				}
				
			}
			
//			for (String key : text.keySet()) {
//				System.out.println(key + " - " + text.get(key));
//			}
			
			readingFileReader.close();
			
			//////////////////////////
			
			System.out.println("Tapping phase duration: " + timeTapping + " s");
			
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		
		/*
		 * Creating the Scenario
		 */
		
		scenario = new Scenario(fileName);
		
		/*
		 * Timers
		 */
		
		tapTimer = new Timer(timeTapping * 1000, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent evt) {
				currentState = STATE.BLANK;
				endOfTrial();
				System.out.println("Trial completed");
			}
			
		});
		
		tapTimer.setRepeats(false);
		
		dialog = new StartDialog(this, expeScreen);
		
		INSTANCE = this;
		
	}
	
	public void initTrial() {
		expeScreen.newTrial();
		nbTaps = 0;
		lastTap = -1;
		tapStarted = false;
		setCanStart(false);
	}
	
	public void startExpe() {
		
		expeScreen = new ExpeScreen(this, fontSize);
		
		scenario.start(participant);
		if (currentTrial != 1) {
			scenario.goTo(Trial, ""+(currentTrial));
		}
		
		initTrial();
	}
	
	public void pressed() {
		
		if (canStart) {
			
			long newLastTap = System.currentTimeMillis();
			
			cineLogManager.logValue(When, ""+newLastTap);
			
			if(!tapStarted) {
				
				tapTimer.start();
				
				cineLogManager.logValue(Duration, "0");
				
				System.out.println("First tap");
				
				tapStarted = true;
				
			} else {
				
				cineLogManager.logValue(Duration, ""+(newLastTap-lastTap));
				
			}
			
			cineLog();
			
			nbTaps++;
			
			lastTap = newLastTap;
			
//			System.out.println("tap");
			
		}
		
	}
	
	private void endOfTrial() {
		log();

		tapStarted = false;
		
		if (!scenario.goOn()) {
			quit();
		}
		currentTrial = Integer.parseInt(scenario.getFactorValue(Trial));
		initTrial();
		
		currentState = STATE.BLANK;
	}
	
	public void log() {
		
		logFactors(logManager);
		
		logManager.logValue(NbTaps, ""+nbTaps);
		logManager.logValue(AverageTapDuration, ""+(1d*nbTaps/(1d*timeTapping)));
		
		// Light log, can be flushed immediately
		logManager.writeLogLine(true, true);
	}
	
	public void cineLog(){
		
		logFactors(cineLogManager);
		
		cineLogManager.writeLogLine(false, false);
		
	}
	
	public void logFactors(LogManager lm) {
		
		logFactor(lm, Trial);
		
		lm.logValue(Participant, ""+participant); // meh...
		
		logFactor(lm, Hand);
		logFactor(lm, Task);
		
		lm.logValue(Session, session.name());
		
	}
			
	public void initLogs() {
		
		/*
		 * Creating the log managers
		 */
		
		Calendar calendar = Calendar.getInstance();
		String date = "" +
			(calendar.get(Calendar.DAY_OF_MONTH) < 10 ? "0" : "") + calendar.get(Calendar.DAY_OF_MONTH) + "-" + 
			(calendar.get(Calendar.MONTH) < 9 ? "0" : "") + (calendar.get(Calendar.MONTH) + 1) + "-" + 
			calendar.get(Calendar.YEAR) + "_" + 
			(calendar.get(Calendar.HOUR_OF_DAY) < 10 ? "0" : "") + calendar.get(Calendar.HOUR_OF_DAY) + "h" +
			(calendar.get(Calendar.MINUTE) < 10 ? "0" : "") + calendar.get(Calendar.MINUTE);
		
		PrintStream out;
		try {
			out = new PrintStream(new FileOutputStream(
					"logs" + File.separatorChar + "errors" + File.separatorChar + 
					"errors_Participant-" + participant + "_"+ session + "_" + date + ".txt"
			));
			System.setErr(out);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		logManager = new LogManager("Trials", "logs" + File.separatorChar + "logs" + File.separatorChar + 
				"Participant-" + participant + "_" + session + "_" + date + ".csv", true, true,
				
				// Scenario
				
				Participant,
				Trial,
				Session,
				
				// Factors
				
				Task,
				Hand,
				
				// Measures
				
				NbTaps,
				AverageTapDuration
		);
		
		cineLogManager = new LogManager(
				"Cinematics",
				"logs" + File.separatorChar + "cinelogs" + File.separatorChar + 
				"Participant-" + participant + "_" + session + "_" + date + ".csv", 
				false, 
				true,
				
				// Scenario
				
				Participant,
				Trial,
				Session,
				
				// Factors
				
				Task,
				Hand,
				
				// Measures
				
				When,
				Duration
				
		);
		
		logManager.setLog(true);
		cineLogManager.setLog(true);
		
		
		/*
		 * 
		 */
		
	}
	
	public void quit() {
		
		quiting = true;
			
		System.out.println("Start flushing log.");
		
		logManager.flush();
		logManager.close();
		
		System.out.println("Log written. Start flushing cinematics.");
		
		cineLogManager.flush();
		cineLogManager.close();
		
		System.out.println("Cinematics written.");
        
		System.exit(0);
		
	}
	
	protected void logFactor(LogManager logManager, String factorName) {
		logManager.logValue(factorName, scenario.getFactorValue(factorName));
	}
	
	public STATE getCurrentState() {
		return currentState;
	}
	
	public void setParticipant(int p) {
		participant = p;
	}
	
	public void setSession(int s) {
		session = SESSION.values()[s];
	}
	
	public void setCurrentTrial(int currentTrial) {
		this.currentTrial = currentTrial;
	}
	
	public void setCanStart(boolean canStart) {
		if (canStart) { 
			expeScreen.readyToTap();
		}
		this.canStart = canStart;
	}
	
	public String getWord(String label) {
		System.out.println(session);
		return language.get(label)[session.ordinal()];
	}
	
	public String getReadingText() {
		return text.get(session.name());
	}
	
	public String getHand() {
		return scenario.getFactorValue(Hand);
	}
	
	public String getTask() {
		return scenario.getFactorValue(Task);
	}
	
	public String getLanguage() {
		return session.name();
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		ScenarioManager manager = new ScenarioManager("experiment_tap.txt");
		
	}
	
}
